package com.centerm.bluetooth.jf;

import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.SparseArray;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.centerm.bluetooth.common.controller.PinController;
import com.centerm.bluetooth.common.controller.TerminalController;
import com.centerm.bluetooth.common.controller.TerminalSafeController;
import com.centerm.bluetooth.common.controller.TradeController;
import com.centerm.bluetooth.common.listener.IPBOCListener;
import com.centerm.bluetooth.common.listener.IPinListener;
import com.centerm.bluetooth.common.listener.ITerminalListener;
import com.centerm.bluetooth.common.listener.ITerminalSafeListener;
import com.centerm.bluetooth.common.listener.ITradeListener;
import com.centerm.bluetooth.common.model.CardInfo;
import com.centerm.bluetooth.common.model.Version;
import com.centerm.bluetooth.core.controller.BluetoothController;
import com.centerm.bluetooth.core.controller.constants.BluetoothState;
import com.centerm.bluetooth.core.listener.IBluetoothFoundListener;
import com.centerm.bluetooth.core.listener.IBluetoothStateListener;
import com.centerm.bluetooth.ibridge.BluetoothIBridgeDevice;
import com.centerm.bluetooth.ibridge.constants.ChannelConfig;
import com.centerm.bluetooth.jf.constants.Template;
import com.centerm.bluetooth.jf.listener.CSwiperStateChangedListener;
import com.centerm.bluetooth.jf.model.SalesSlipModel;
import com.centerm.util.HexUtil;
import com.centerm.util.Logger;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by linwenhui on 2017/5/6.
 */

public class CCTSwiperController {
    private final static SparseArray<String> handBrushWay = new SparseArray<>();

    static {
        handBrushWay.put(0, "100101");//手刷磁条
        handBrushWay.put(1, "100102");//手刷IC
        handBrushWay.put(2, "100103");//非接挥卡
    }

    private BluetoothController bluetoothController;
    private TerminalController terminalController;
    private TradeController tradeController;
    private PinController pinController;
    private JFPBOCController pbocController;
    private TerminalSafeController terminalSafeController;
    private POSImp posImp;
    private CSwiperStateChangedListener cSwiperStateChangedListener;
    private int money;
    private BluetoothIBridgeDevice curDev;
    private byte[] random, orderId;
    private static Handler mainHandler = new Handler();
    private Timer connectingTimer;
    private int timeout;
    private int cardType;

    public CCTSwiperController(Context context, CSwiperStateChangedListener cSwiperStateChangedListener) {
        this.cSwiperStateChangedListener = cSwiperStateChangedListener;
        ChannelConfig.getInstance().setChannel(ChannelConfig.CENTERM);
        bluetoothController = BluetoothController.getInstance(context);
        BluetoothStateImp bluetoothStateImp = new BluetoothStateImp();
        bluetoothController.setBluetoothStateListener(bluetoothStateImp);
        bluetoothController.setBluetoothFoundListener(bluetoothStateImp);
        posImp = new POSImp();
        terminalController = new TerminalController(context);
        terminalController.setListener(posImp);
        tradeController = new TradeController(context);
        tradeController.setListener(posImp);
        pinController = new PinController(context);
        pinController.setListener(posImp);
        pbocController = new JFPBOCController(context);
        pbocController.setListener(posImp);
        terminalSafeController = new TerminalSafeController(context);
        terminalSafeController.setListener(posImp);
    }

    /**
     * 检测音频
     *
     * @param DetectTime 毫秒
     */
    public void onDetecteAudio(int DetectTime) {
    }

    public void onStartSearchBluetooth() {
        bluetoothController.startDiscovery();
    }

    public void onStopSearchBluetooth() {
        bluetoothController.stopDiscovery();
    }

    /**
     * 连接蓝牙刷卡器;
     *
     * @param bondTime 秒
     * @param address  蓝牙地址
     */
    public void onConnectBluetooth(int bondTime, @NonNull String address) {
        if (bondTime > 0) {
            if (connectingTimer != null)
                connectingTimer.cancel();
            connectingTimer = new Timer();
            connectingTimer.schedule(new ConnnectingTask(), bondTime);
        }
        curDev = BluetoothIBridgeDevice.createBluetoothIBridgeDevice(address.toUpperCase());
        bluetoothController.connect(curDev);
    }

    /**
     * 获取Ksn
     *
     * @return
     */
    public void onGetKsn() {
        posImp.setReturnKSN(true);
        try {
            terminalController.getPSAMAndTerminalId();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 当前刷卡器设备是否可用
     *
     * @return
     */
    public boolean isDevicePresent() {
        if (curDev != null)
            return curDev.isConnected();
        return false;
    }

    /**
     * 设置金额。
     *
     * @param amount         金额
     * @param amountDescribe 交易描述
     * @param currencyCode   货币代码，一般是156代表人民币
     * @param type           交易类型，一般是查余和支付，Template.FLAG_PAY_QUERY/Template.FLAG_PAY_TRADE
     */
    public void setAmount(String amount, String amountDescribe, String currencyCode, int type) {
        if (type == Template.FLAG_PAY_QUERY)
            money = -1;
        else
            try {
                money = Integer.valueOf(amount);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
    }

    /**
     * 启动刷卡
     *
     * @param ctrlmode
     * @param random
     * @param appendData
     * @param timeout
     */
    public void onStartCSwiper(int ctrlmode, byte[] random, byte[] appendData, int timeout) {
        this.random = random;
        this.orderId = appendData;
        this.timeout = timeout;
        try {
            tradeController.openCardReader(random, timeout, money);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 根据字符串打印签购单
     *
     * @param data
     * @return
     */
    public boolean onPrintData(String data) {
        return false;
    }

    public boolean onPrintData(SalesSlipModel model) {
        return false;
    }

    /**
     * 停止设备，但未断开蓝牙连接
     */
    public void stopCSwiper() {
        try {
            terminalController.reset();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 断开 刷卡器固件 蓝牙
     */
    public void disconnectBT() {
        if (curDev != null && curDev.isConnected())
            bluetoothController.disconnect(curDev);
    }

    private class ConnnectingTask extends TimerTask {

        @Override
        public void run() {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onConnectTimeout();
                }
            });
        }
    }

    private class BluetoothStateImp implements IBluetoothStateListener, IBluetoothFoundListener {
        @Override
        public void onBluetoothStateChange(BluetoothState state) {
            if (curDev != null)
                curDev = BluetoothIBridgeDevice.createBluetoothIBridgeDevice(curDev.getDeviceAddress());
            if (state == BluetoothState.CONNECTED) {
                if (connectingTimer != null)
                    connectingTimer.cancel();
                connectingTimer = null;
                if (cSwiperStateChangedListener != null)
                    cSwiperStateChangedListener.onBluetoothBounded();
                posImp.setReturnKSN(false);
                try {
                    terminalController.getPSAMAndTerminalId();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else if (state == BluetoothState.CONNECTTING) {
                if (cSwiperStateChangedListener != null)
                    cSwiperStateChangedListener.onBluetoothBounding();
            } else if (state == BluetoothState.DISCONNECTED) {
            }
        }

        @Override
        public void onDeviceFound(final BluetoothIBridgeDevice device) {
            Logger.i(" == onDeviceFound == ");
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null) {
                        cSwiperStateChangedListener.onDeviceFind(BluetoothAdapter.getDefaultAdapter().getRemoteDevice(device.getDeviceAddress()));
                    }
                }
            });

        }

        @Override
        public void onDiscoveryFinished() {

        }
    }

    private class POSImp implements ITerminalListener, ITradeListener, IPinListener, IPBOCListener, ITerminalSafeListener {
        private String ksn;
        private boolean returnKSN;
        private CardInfo cardInfo = new CardInfo();

        public void setReturnKSN(boolean returnKSN) {
            this.returnKSN = returnKSN;
        }

        @Override
        public void onError(int code, String msg) {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onError(Template.ERROR_HARSET, Template.ERROR_HARSET_STRING);
                }
            });
        }

        @Override
        public void onTimeout() {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onInterrupted();
                }
            });
        }

        @Override
        public void onGetVersion(Version version) {

        }

        @Override
        public void onReset() {

        }

        @Override
        public void onGetPSAMAndTerminal(final String psamAndTerminal) {
            ksn = psamAndTerminal;
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (returnKSN && cSwiperStateChangedListener != null) {
                        cSwiperStateChangedListener.onGetKsnCompleted(psamAndTerminal);
                    }
                }
            });

        }

        @Override
        public void onWaitForSwipeCard() {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onWaitingForCardSwipe();
                }
            });
            cardInfo.clear();
        }

        @Override
        public void onSwiperSuc() {
            if (cSwiperStateChangedListener != null)
                cSwiperStateChangedListener.onDetectTrack();
            cardType = 0;
            try {
                tradeController.getTradeData();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onSwiperFalse() {
            tradeController.registerSwiperCardResult();
        }

        @Override
        public void onSwiperTimeout() {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onSwipeCardTimeout();
                }
            });
        }

        @Override
        public void onCancelSwipeCard() {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onError(Template.ERROR_SWIPER_CANCEL, Template.ERROR_SWIPER_CANCEL_STRING);
                }
            });
        }

        @Override
        public void onICInsert() {
            if (cSwiperStateChangedListener != null)
                cSwiperStateChangedListener.onDetectIC();
            cardType = 1;
            String moneyString;
            if (money >= 0) {
                moneyString = String.format("%012d", money);
            } else {
                moneyString = "FFFFFFFFFFFF";
            }
            try {
                pbocController.startPBOC(moneyString);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onNFInsert() {
            if (cSwiperStateChangedListener != null)
                cSwiperStateChangedListener.onDetectIC();
            cardType = 2;
            String moneyString;
            if (money >= 0) {
                moneyString = String.format("%012d", money);
            } else {
                moneyString = "FFFFFFFFFFFF";
            }
            try {
                pbocController.startQPBOC(moneyString);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onCardType(int cardType) {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onError(Template.ERROR_SWIPER_FAILURE, Template.ERROR_SWIPER_FAILURE_STRING);
                }
            });
        }

        @Override
        public void onSwiperCompelete(String result) {
            JSONObject params = JSON.parseObject(result);
            cardInfo.setTradeTwo(params.getString("tradeTwo"));
            cardInfo.setTradeThree(params.getString("tradeThree"));
            cardInfo.setTrade(params.getString("tradeTwo") + params.getString("tradeThree"));
            cardInfo.setTradeRandom(params.getString("random"));
            cardInfo.setPan(params.getString("pan"));
            cardInfo.setExpireDate(params.getString("expireDate"));
            String moneyString;
            if (money >= 0) {
                moneyString = String.format("%012d", money);
            } else {
                moneyString = "FFFFFFFFFFFF";
            }
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onDetectTrack();
                }
            });
            try {
                pinController.startInputPin(timeout, moneyString);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onGetInputPin(byte[] pinblock, byte[] random) {
            cardInfo.setPinBlock(HexUtil.byte2HexStr(pinblock));
            cardInfo.setPinBlockRandom(HexUtil.byte2HexStr(random));
            StringBuilder macBuilder = new StringBuilder();
            //磁道密文(如果是磁条卡：二三磁条)
            macBuilder.append(cardInfo.getTrade());
            //磁道加密中由终端生成的随机数
            macBuilder.append(cardInfo.getTradeRandom());
            //20字节终端号+16字节psam号
            macBuilder.append(ksn);
            //32字节订单号
            macBuilder.append(HexUtil.byte2HexStr(orderId));
            try {
                terminalSafeController.calMac(CCTSwiperController.this.random, HexUtil.hexStr2Bytes(macBuilder.toString()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onInputPinEmpty() {
            cardInfo.setPinBlock("FFFFFFFFFFFFFFF");
            cardInfo.setPinBlockRandom("FFFFFFFF");
            StringBuilder macBuilder = new StringBuilder();
            //磁道密文(如果是磁条卡：二三磁条)
            macBuilder.append(cardInfo.getTrade());
            //磁道加密中由终端生成的随机数
            macBuilder.append(cardInfo.getTradeRandom());
            //20字节终端号+16字节psam号
            macBuilder.append(ksn);
            //32字节订单号
            macBuilder.append(HexUtil.byte2HexStr(orderId));
            try {
                terminalSafeController.calMac(CCTSwiperController.this.random, HexUtil.hexStr2Bytes(macBuilder.toString()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onWaitForInputPin() {

        }

        @Override
        public void onInputPinCancel() {
            if (cardType != 0)
                try {
                    pbocController.endPBOC(1);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onTradeCancel();
                }
            });
        }

        @Override
        public void onInputPinTimeout() {
            if (cardType != 0)
                try {
                    pbocController.endPBOC(1);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onError(Template.ERROR_INPUT_PIN_TIMEOUT, Template.ERROR_INPUT_PIN_TIMEOUT_STRING);
                }
            });
        }

        @Override
        public void onWaitForPBOCResult() {

        }

        @Override
        public void onPBOCResult(String result) {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onDetectIC();
                }
            });
            Logger.i(result);
            JSONObject params = JSON.parseObject(result);
            cardInfo.setTrade(params.getString("icdata"));
            cardInfo.setTradeTwo(params.getString("tradeTwo"));
            cardInfo.setTradeRandom(params.getString("random"));
            cardInfo.setPan(params.getString("pan"));
            cardInfo.setExpireDate(params.getString("expireDate"));
            cardInfo.setCardSerial(params.getString("cardSerail"));
            cardInfo.setName(params.getString("name"));
            String moneyString;
            if (money >= 0) {
                moneyString = String.format("%012d", money);
            } else {
                moneyString = "FFFFFFFFFFFF";
            }

            try {
                pinController.startInputPin(timeout, moneyString);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onEndPBOC() {
            try {
                terminalController.reset();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onPBOCError() {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null)
                        cSwiperStateChangedListener.onError(Template.ERROR_READ_CARD_FAILURE, Template.ERROR_READ_CARD_FAILURE_STRING);
                }
            });
        }

        @Override
        public void onGetMac(final byte[] mac) {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (cSwiperStateChangedListener != null) {
                        int tradeTwoLen = 0;
                        if (!TextUtils.isEmpty(cardInfo.getTradeTwo()))
                            tradeTwoLen = cardInfo.getTradeTwo().length();

                        int tradeThreeLen = 0;
                        if (!TextUtils.isEmpty(cardInfo.getTradeThree()))
                            tradeTwoLen = cardInfo.getTradeThree().length();

                        cSwiperStateChangedListener.onDecodeCompleted(null, ksn, cardInfo.getTradeTwo() + (TextUtils.isEmpty(cardInfo.getTradeThree()) ? "" : cardInfo.getTradeThree()),
                                0, tradeTwoLen, tradeThreeLen, cardInfo.getTradeRandom(), cardInfo.getPan(), cardInfo.getExpireDate(), cardInfo.getName(), cardType + "",
                                HexUtil.byte2HexStr(mac), cardType == 0 ? "" : cardInfo.getTrade(), cardType != 0, cardInfo.getPinBlock() + cardInfo.getPinBlockRandom(), handBrushWay.get(cardType));
                    }
                }
            });

            if (cardType != 0)
                try {
                    pbocController.endPBOC(0);
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
}
